#pragma once

#include "../mq_comm/mq_helper.hpp"
#include "../mq_comm/mq_log.hpp"
#include "../mq_comm/mq_msg.pb.h"

#include <iostream>
#include <unordered_map>
#include <mutex>
#include <vector>
#include <string>
#include <functional>
#include <memory>

namespace mq
{
    using namespace Ns_Log;
    using ConsumerCallBack = std::function<void(const std::string, const BasicProperties *bp, const std::string)>;

    struct Consumer
    {
        using ptr = std::shared_ptr<Consumer>;

        std::string tag;   // 消费者标识
        std::string qname; // 消费者订阅的队列名称
        bool auto_ack;     // 是否自动应答
        ConsumerCallBack callback;

        Consumer()
        {
        }
        Consumer(const std::string &ctag, const std::string &queue_name, bool ack_flag, const ConsumerCallBack &cb) : tag(ctag), qname(queue_name), auto_ack(ack_flag), callback(cb)
        {
        }
    };
    // 以队列为单元的消费者管理结构
    class QueueConsumer
    {
    public:
        using ptr = std::shared_ptr<QueueConsumer>;
        QueueConsumer(const std::string &qname) : _qname(qname)
        {
        }
        // 新增消费者
        Consumer::ptr create(const std::string &ctag, const std::string &queue_name, bool ack_flag, const ConsumerCallBack &cb)
        {
            // 加锁
            std::unique_lock<std::mutex> lock(_mtx);
            // 判断是否已经存在
            for (auto &consumer : _consumers)
            {
                if (consumer->tag == ctag)
                    return consumer;
            }
            // 没有重复存在, 构造对象
            auto consumer = std::make_shared<Consumer>(ctag, queue_name, ack_flag, cb);
            // 添加到vector进行管理, 返回对象
            _consumers.push_back(consumer);
            return consumer;
        }
        // 队列移除消费者
        void remove(const std::string &ctag)
        {
            // 加锁
            std::unique_lock<std::mutex> lock(_mtx);
            // 查找 -- 删除
            for (auto it = _consumers.begin(); it != _consumers.end(); ++it)
            {
                if ((*it)->tag == ctag)
                {
                    _consumers.erase(it);
                    return;
                }
            }
            return;
        }
        // 队列获取消费者：RR轮转获取
        Consumer::ptr choose()
        {
            // 加锁
            std::unique_lock<std::mutex> lock(_mtx);
            if (_consumers.size() == 0)
            {
                return Consumer::ptr();
            }
            // 计算轮转下标
            int idx = _rr_seq % _consumers.size();
            _rr_seq++;
            // 获取对象, 返回
            return _consumers[idx];
        }
        bool empty()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            return _consumers.size() == 0;
        }
        bool exists(const std::string &ctag)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            for (auto &consumer : _consumers)
            {
                if (consumer->tag == ctag)
                    return true;
            }
            return false;
        }
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            _rr_seq = 0;
            _consumers.clear();
        }

    private:
        std::string _qname;
        std::mutex _mtx;
        uint64_t _rr_seq; // 轮转序列号

        std::vector<Consumer::ptr> _consumers;
    };
    class ConsumerManager
    {
    public:
        using ptr = std::shared_ptr<ConsumerManager>;
        ConsumerManager()
        {
        }
        // 初始胡队列的消费者管理句柄, 构建映射
        void initQueueConsumer(const std::string &qname)
        {
            // 加锁
            std::unique_lock<std::mutex> lock(_mtx);
            // 判断是否已经存在
            auto it = _qconsumers.find(qname);
            if (it != _qconsumers.end())
            {
                return;
            }
            // 构建对象
            auto qconsumer = std::make_shared<QueueConsumer>(qname);
            // 新增管理
            _qconsumers.insert(std::make_pair(qname, qconsumer));
        }
        // 销毁整个队列的消费者管理类
        void destroyQueueConsumer(const std::string &qname)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            _qconsumers.erase(qname);
        }
        // 消费者订阅某个队列
        Consumer::ptr create(const std::string &ctag, const std::string &qname, bool ack_flag, const ConsumerCallBack &cb)
        {
            QueueConsumer::ptr qcp;
            {
                // 加锁
                std::unique_lock<std::mutex> lock(_mtx);
                // 查找管理句柄
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    LOG(ERROR) << "没有找到队列 " << qname << " 的消费者管理句柄!\n";
                    return Consumer::ptr();
                }
                qcp = it->second;
            }
            return qcp->create(ctag, qname, ack_flag, cb);
        }
        // 取消订阅
        void remove(const std::string &ctag, const std::string &qname)
        {
            QueueConsumer::ptr qcp;
            {
                // 加锁
                std::unique_lock<std::mutex> lock(_mtx);
                // 查找管理句柄
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    LOG(ERROR) << "没有找到队列 " << qname << " 的消费者管理句柄!\n";
                    return ;
                }
                qcp = it->second;
            }
            qcp->remove(ctag);
        }
        // 获取订阅了某个队列的任意一个消费者, 然后推送消息
        // 原理是遍历订阅队列的消费者vector, 依次推送
        Consumer::ptr choose(const std::string &qname)
        {
            QueueConsumer::ptr qcp;
            {
                // 加锁
                std::unique_lock<std::mutex> lock(_mtx);
                // 查找管理句柄
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    LOG(ERROR) << "没有找到队列 " << qname << " 的消费者管理句柄!\n";
                    return Consumer::ptr();
                }
                qcp = it->second;
            }
            return qcp->choose();
        }
        bool empty(const std::string qname)
        {
            QueueConsumer::ptr qcp;
            {
                // 加锁
                std::unique_lock<std::mutex> lock(_mtx);
                // 查找管理句柄
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    LOG(ERROR) << "没有找到队列 " << qname << " 的消费者管理句柄!\n";
                    return false;
                }
                qcp = it->second;
            }
            return qcp->empty();
        }
        // 判断是否订阅
        bool exists(const std::string &ctag, const std::string &qname)
        {
            QueueConsumer::ptr qcp;
            {
                // 加锁
                std::unique_lock<std::mutex> lock(_mtx);
                // 查找管理句柄
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    LOG(ERROR) << "没有找到队列 " << qname << " 的消费者管理句柄!\n";
                    return false;
                }
                qcp = it->second;
            }
            return qcp->exists(ctag);
        }
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            _qconsumers.clear();
        }
    private:
        std::mutex _mtx;
        std::unordered_map<std::string, QueueConsumer::ptr> _qconsumers; // 队列名 与 队列中消费者管理类的映射关系
    };
}